
#define _FILE_OFFSET_BITS 64
#define FUSE_USE_VERSION 26

#include <errno.h>
#include <fcntl.h>
#include <string.h>
#include <osxfuse/fuse.h>

#include <syslog.h>

#include "SQLiteFs.h"

SQLiteFs* g_sqliteFileSystem;

#pragma mark - general

static int
sqlite_fs_getattr(const char *path, struct stat *stbuf)
{
    syslog(LOG_NOTICE, "%s()", __FUNCTION__);
    
    return g_sqliteFileSystem->getAttributes(path, stbuf);
}

static int
sqlite_fs_rename(const char* path, const char* newPath)
{
    syslog(LOG_NOTICE, "%s()", __FUNCTION__);
    
    return g_sqliteFileSystem->rename(path, newPath);
}

#pragma mark - folders

static int
sqlite_fs_mkdir(const char* path, mode_t mode)
{
    syslog(LOG_NOTICE, "%s()", __FUNCTION__);
    
    return g_sqliteFileSystem->createDirectory(path, mode);
}

static int
sqlite_fs_rmdir(const char* path)
{
    syslog(LOG_NOTICE, "%s()", __FUNCTION__);

    return g_sqliteFileSystem->removeDirectory(path);    
}

static int
sqlite_fs_readdir(const char *path, void *buf, fuse_fill_dir_t filler,
                  off_t offset, struct fuse_file_info *fi)
{
    syslog(LOG_NOTICE, "%s()", __FUNCTION__);
    
    return g_sqliteFileSystem->readDirectory(path, buf, filler, offset, fi);
}

#pragma mark - files

//static int
//sqlite_fs_create(const char* fileName, mode_t mode, struct fuse_file_info* fileInfo)
//{
//    syslog(LOG_NOTICE, "%s()", __FUNCTION__);
//    
//    std::unique_ptr<InMemoryFile> file;
//    bool created = g_memoryFileSystem.createFile(fileName, &file);
//    if (!created)
//        return -EACCES;
//    
//    fileInfo->fh = reinterpret_cast<uint64_t>(file.get());
//    file.release();
//    
//    return 0;
//}
//
//static int
//sqlite_fs_unlink(const char* fileName)
//{
//    syslog(LOG_NOTICE, "%s()", __FUNCTION__);
//    
//    g_memoryFileSystem.remove(fileName);
//    
//    return 0;
//}
//
//static int
//sqlite_fs_open(const char* path, struct fuse_file_info* fileInfo)
//{
//    syslog(LOG_NOTICE, "%s()", __FUNCTION__);
//    
//    std::unique_ptr<InMemoryFile> file;
//    bool created = g_memoryFileSystem.openFile(path, &file);
//    if (!created)
//        return -EACCES;
//    
//    fileInfo->fh = reinterpret_cast<uint64_t>(file.get());
//    file.release();
//    
//    return 0;
//    
//}
//
//static int
//sqlite_fs_release(const char *path, struct fuse_file_info *fi)
//{
//    syslog(LOG_NOTICE, "%s()", __FUNCTION__);
//    
//    InMemoryFile* file = reinterpret_cast<InMemoryFile*>(fi->fh);
//    delete file;
//    
//    return 0;
//}
//
//static int
//sqlite_fs_read(const char *path, char *buf, size_t size, off_t offset,
//               struct fuse_file_info* fileInfo)
//{
//    syslog(LOG_NOTICE, "%s()", __FUNCTION__);
//    
//    InMemoryFile* file = reinterpret_cast<InMemoryFile*>(fileInfo->fh);
//    if (file)
//    {
//        size_t read = file->read(buf, size, offset);
//        return static_cast<int>(read);
//    }
//    
//    return 0;
//}
//
//static int
//sqlite_fs_write(const char* path, const char* buf, size_t size, off_t offset, struct fuse_file_info* fileInfo)
//{
//    syslog(LOG_NOTICE, "%s()", __FUNCTION__);
//    
//    InMemoryFile* file = reinterpret_cast<InMemoryFile*>(fileInfo->fh);
//    if (file)
//    {
//        size_t written = file->write(buf, size, offset);
//        return static_cast<int>(written);
//    }
//    
//    return 0;
//}
//
//static int
//sqlite_fs_truncate(const char* path, off_t newSize)
//{
//    syslog(LOG_NOTICE, "%s()", __FUNCTION__);
//    
//    bool truncated = g_memoryFileSystem.truncateFile(path, newSize);
//    if (!truncated)
//        return -EACCES;
//    
//    return 0;
//}

static struct fuse_operations sqlite_fs_filesystem_operations = {
    .getattr = sqlite_fs_getattr, /* To provide size, permissions, etc. */
//    .create  = sqlite_fs_create,
//    .unlink  = sqlite_fs_unlink,
//    .open    = sqlite_fs_open,    /* To enforce read-only access.       */
//    .read    = sqlite_fs_read,    /* To provide file content.           */
//    .write   = sqlite_fs_write,
//    .truncate = sqlite_fs_truncate,
//    .release = sqlite_fs_release,
    .readdir = sqlite_fs_readdir, /* To provide directory listing.      */
    .mkdir   = sqlite_fs_mkdir,
    .rmdir   = sqlite_fs_rmdir,
    .rename  = sqlite_fs_rename
};

int
main(int argc, char **argv)
{
    g_sqliteFileSystem = new SQLiteFs("test.db");
    
    return fuse_main(argc, argv, &sqlite_fs_filesystem_operations, NULL);
}
